/**
 ******************************************************************************
 * @file           : bsp_rs485.c
 * @brief          : RS485 Driver Implementation (STM32F4xx)
 ******************************************************************************
 * @attention
 *
 * RS485驱动实现文件
 * 使用USART + DE引脚实现半双工通信
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/RS485/bsp_rs485.h"
#include "./BSP/RS485/bsp_rs485_config.h"
#include <string.h>

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static UART_HandleTypeDef sg_rs485_handle;
static volatile RS485_Error_e sg_rs485_last_error = RS485_OK;  /*!< RS485最后一次错误 */
static volatile RS485_State_e sg_rs485_state = RS485_STATE_IDLE;  /*!< RS485当前状态 */

/* 接收缓冲区（环形缓冲区） */
static uint8_t sg_rx_buffer[RS485_RX_BUF_SIZE];
static volatile uint16_t sg_rx_write_index = 0;
static volatile uint16_t sg_rx_read_index = 0;
static volatile uint16_t sg_rx_count = 0;

/* Private function prototypes -----------------------------------------------*/
static void rs485_gpio_init(void);
static void rs485_de_init(void);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       RS485 USART GPIO初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        STM32F4xx使用GPIO AF复用功能
 */
static void rs485_gpio_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};

    /* 使能GPIO时钟 */
    RS485_TX_GPIO_CLK_ENABLE();
    RS485_RX_GPIO_CLK_ENABLE();

    /* 配置TX引脚（复用推挽输出） */
    gpio_init_struct.Pin = RS485_TX_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    gpio_init_struct.Alternate = RS485_GPIO_AF;  /* 配置AF功能 */
    HAL_GPIO_Init(RS485_TX_GPIO_PORT, &gpio_init_struct);

    /* 配置RX引脚（复用推挽输入） */
    gpio_init_struct.Pin = RS485_RX_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    gpio_init_struct.Alternate = RS485_GPIO_AF;  /* 配置AF功能 */
    HAL_GPIO_Init(RS485_RX_GPIO_PORT, &gpio_init_struct);
}

/**
 * @brief       RS485 DE引脚初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        DE引脚控制收发方向
 */
static void rs485_de_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};

    /* 使能DE引脚GPIO时钟 */
    RS485_DE_GPIO_CLK_ENABLE();

    /* 配置DE引脚为推挽输出 */
    gpio_init_struct.Pin = RS485_DE_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init_struct.Pull = GPIO_NOPULL;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(RS485_DE_GPIO_PORT, &gpio_init_struct);

    /* 默认为接收模式 */
    RS485_RX_ENABLE();
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       RS485初始化
 *
 * @param[in]   baudrate 波特率
 *
 * @retval      无
 *
 * @note        配置为8位数据，1位停止位，无校验
 */
void rs485_init(uint32_t baudrate)
{
    /* 使能USART时钟 */
    RS485_UARTx_CLK_ENABLE();

    /* 初始化GPIO */
    rs485_gpio_init();
    rs485_de_init();

    /* 配置USART */
    sg_rs485_handle.Instance = RS485_UARTx;
    sg_rs485_handle.Init.BaudRate = baudrate;
    sg_rs485_handle.Init.WordLength = UART_WORDLENGTH_8B;
    sg_rs485_handle.Init.StopBits = UART_STOPBITS_1;
    sg_rs485_handle.Init.Parity = UART_PARITY_NONE;
    sg_rs485_handle.Init.Mode = UART_MODE_TX_RX;
    sg_rs485_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    sg_rs485_handle.Init.OverSampling = UART_OVERSAMPLING_16;

    if (HAL_UART_Init(&sg_rs485_handle) != HAL_OK)
    {
        log_e("RS485 USART initialization failed");
        return;
    }

    /* 配置中断优先级并使能 */
    HAL_NVIC_SetPriority(RS485_UARTx_IRQn, 3, 0);
    HAL_NVIC_EnableIRQ(RS485_UARTx_IRQn);

    /* 使能接收中断 */
    __HAL_UART_ENABLE_IT(&sg_rs485_handle, UART_IT_RXNE);

    /* 清空接收缓冲区 */
    sg_rx_write_index = 0;
    sg_rx_read_index = 0;
    sg_rx_count = 0;

    /* 默认为接收模式 */
    RS485_RX_ENABLE();

    log_i("RS485 initialized: USART%d, %u baud", RS485_USART_SELECT, baudrate);
}

/**
 * @brief       RS485去初始化
 *
 * @param       无
 *
 * @retval      无
 */
void rs485_deinit(void)
{
    /* 禁用中断 */
    HAL_NVIC_DisableIRQ(RS485_UARTx_IRQn);

    /* 去初始化USART */
    HAL_UART_DeInit(&sg_rs485_handle);

    log_i("RS485 deinitialized");
}

/**
 * @brief       发送单个字节
 *
 * @param[in]   data 要发送的字节
 *
 * @retval      无
 *
 * @note        自动切换收发方向
 */
void rs485_send_byte(uint8_t data)
{
    /* 切换到发送模式 */
    RS485_TX_ENABLE();
    RS485_DELAY_US(10);  /* 短暂延时确保切换完成 */

    /* 发送数据 */
    HAL_UART_Transmit(&sg_rs485_handle, &data, 1, HAL_MAX_DELAY);

    /* 等待发送完成 */
    while (__HAL_UART_GET_FLAG(&sg_rs485_handle, UART_FLAG_TC) == RESET);

    /* 延时确保最后一个字节发送完毕 */
    RS485_DELAY_US(100);

    /* 切换到接收模式 */
    RS485_RX_ENABLE();
}

/**
 * @brief       发送多个字节
 *
 * @param[in]   buf 数据缓冲区
 * @param[in]   len 数据长度
 *
 * @retval      无
 */
void rs485_send_bytes(const uint8_t *buf, uint16_t len)
{
    if (buf == NULL || len == 0)
    {
        return;
    }

    /* 切换到发送模式 */
    RS485_TX_ENABLE();
    RS485_DELAY_US(10);

    /* 发送数据 */
    HAL_UART_Transmit(&sg_rs485_handle, (uint8_t *)buf, len, HAL_MAX_DELAY);

    /* 等待发送完成 */
    while (__HAL_UART_GET_FLAG(&sg_rs485_handle, UART_FLAG_TC) == RESET);

    /* 延时确保最后一个字节发送完毕 */
    RS485_DELAY_US(100);

    /* 切换到接收模式 */
    RS485_RX_ENABLE();

    log_d("RS485 sent %u bytes", len);
}

/**
 * @brief       发送字符串
 *
 * @param[in]   str 字符串
 *
 * @retval      无
 */
void rs485_send_string(const char *str)
{
    if (str == NULL)
    {
        return;
    }

    rs485_send_bytes((const uint8_t *)str, strlen(str));
}

/**
 * @brief       获取接收缓冲区数据量
 *
 * @param       无
 *
 * @retval      缓冲区中的字节数
 */
uint16_t rs485_get_rx_count(void)
{
    return sg_rx_count;
}

/**
 * @brief       读取单个字节
 *
 * @param       无
 *
 * @retval      读取的字节（无数据返回0）
 */
uint8_t rs485_read_byte(void)
{
    uint8_t data = 0;

    if (sg_rx_count > 0)
    {
        data = sg_rx_buffer[sg_rx_read_index];
        sg_rx_read_index = (sg_rx_read_index + 1) % RS485_RX_BUF_SIZE;
        sg_rx_count--;
    }

    return data;
}

/**
 * @brief       读取多个字节
 *
 * @param[out]  buf 数据缓冲区
 * @param[in]   len 要读取的长度
 *
 * @retval      实际读取的字节数
 */
uint16_t rs485_read_bytes(uint8_t *buf, uint16_t len)
{
    uint16_t i;
    uint16_t count = 0;

    if (buf == NULL || len == 0)
    {
        return 0;
    }

    for (i = 0; i < len && sg_rx_count > 0; i++)
    {
        buf[i] = rs485_read_byte();
        count++;
    }

    return count;
}

/**
 * @brief       清空接收缓冲区
 *
 * @param       无
 *
 * @retval      无
 */
void rs485_flush_rx_buffer(void)
{
    sg_rx_write_index = 0;
    sg_rx_read_index = 0;
    sg_rx_count = 0;
}

/**
 * @brief       RS485中断服务函数
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        在stm32f4xx_it.c中调用此函数
 */
void RS485_UARTx_IRQHandler(void)
{
    uint8_t data;

    /* 接收中断 */
    if (__HAL_UART_GET_FLAG(&sg_rs485_handle, UART_FLAG_RXNE) != RESET)
    {
        /* 读取数据 */
        data = (uint8_t)(sg_rs485_handle.Instance->DR & 0xFF);

        /* 写入环形缓冲区 */
        if (sg_rx_count < RS485_RX_BUF_SIZE)
        {
            sg_rx_buffer[sg_rx_write_index] = data;
            sg_rx_write_index = (sg_rx_write_index + 1) % RS485_RX_BUF_SIZE;
            sg_rx_count++;
        }
        else
        {
            /* 缓冲区满，丢弃最旧的数据 */
            sg_rx_read_index = (sg_rx_read_index + 1) % RS485_RX_BUF_SIZE;
            sg_rx_buffer[sg_rx_write_index] = data;
            sg_rx_write_index = (sg_rx_write_index + 1) % RS485_RX_BUF_SIZE;
        }

        /* 清除接收标志 */
        __HAL_UART_CLEAR_FLAG(&sg_rs485_handle, UART_FLAG_RXNE);
    }

    /* 溢出错误处理 */
    if (__HAL_UART_GET_FLAG(&sg_rs485_handle, UART_FLAG_ORE) != RESET)
    {
        __HAL_UART_CLEAR_OREFLAG(&sg_rs485_handle);
    }
}

/**
 * @brief       获取RS485最后一次错误
 *
 * @param       无
 *
 * @retval      RS485错误码
 */
RS485_Error_e rs485_get_last_error(void)
{
    return sg_rs485_last_error;
}

/**
 * @brief       获取RS485当前状态
 *
 * @param       无
 *
 * @retval      RS485状态
 */
RS485_State_e rs485_get_state(void)
{
    return sg_rs485_state;
}

/**
 * @brief       打印RS485状态（调试接口）
 *
 * @param       无
 *
 * @retval      无
 */
void rs485_print_status(void)
{
    const char *state_str[] = {
        "IDLE",
        "TX",
        "RX",
        "ERROR"
    };
    const char *error_str[] = {
        "RS485_OK",
        "RS485_ERROR_PARAM",
        "RS485_ERROR_TIMEOUT",
        "RS485_ERROR_BUSY",
        "RS485_ERROR_HAL"
    };
    
    if (sg_rs485_state < 4)
    {
        log_i("RS485 State: %s", state_str[sg_rs485_state]);
    }
    
    if (sg_rs485_last_error < 5)
    {
        log_i("RS485 Last Error: %s", error_str[sg_rs485_last_error]);
    }
    
    log_i("RS485 RX Count: %u", sg_rx_count);
}
